# 导入所需库
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# ===== 问题1：数据预处理与弱分类器构建 =====
# 加载数据
data = load_iris()
X = data.data[:100]
y = data.target[:100]

# 数据标准化
scaler = StandardScaler()
X = scaler.fit_transform(X)

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 弱分类器函数
def weak_classifier(X, feature_index, threshold):
    # 确保X是二维数组
    if X.ndim == 1:
        X = X.reshape(1, -1)  # 将一维数组转为二维
    return np.where(X[:, feature_index] >= threshold, 1, -1)

# 构建多个弱分类器
M = 10
classifiers = []
accuracies = []

for i in range(M):
    feature_index = i % 4
    threshold = np.random.uniform(np.min(X_train[:, feature_index]), 
                                np.max(X_train[:, feature_index]))
    classifiers.append((feature_index, threshold))
    
    predictions = weak_classifier(X_train, feature_index, threshold)
    accuracy = np.sum(predictions == y_train) / len(y_train)
    accuracies.append(accuracy)

# 打印弱分类器准确率
for j, acc in enumerate(accuracies):
    print(f"弱分类器{j+1}准确率: {acc:.4f}")

# ===== 问题2：QBoost建模与QUBO转化 =====
# QUBO模型
def QUBO_model(w, X_train, y_train, classifiers, lambda_reg=0.1):
    error = 0
    for i in range(len(X_train)):
        prediction = np.sum(
            [w[j] * weak_classifier(X_train[i], classifiers[j][0], classifiers[j][1]) 
            for j in range(len(classifiers))])
        error += (prediction - y_train[i]) ** 2
    
    regularization = lambda_reg * np.sum(w)
    return error + regularization

# 模拟退火算法
def simulated_annealing(Q, max_iter=1000, T_start=100, T_end=1e-3):
    w = np.random.choice([0, 1], size=len(classifiers))
    T = T_start
    best_w = w.copy()
    best_energy = Q(w)
    
    for t in range(max_iter):
        new_w = w.copy()
        flip_index = np.random.randint(0, len(w))
        new_w[flip_index] = 1 - new_w[flip_index]
        
        energy = Q(new_w)
        if energy < best_energy or np.random.rand() < np.exp((best_energy - energy) / T):
            w = new_w
            best_energy = energy
        T = max(T_end, T * 0.99)
    
    return best_w

# 求解最优组合
best_weights = simulated_annealing(lambda w: QUBO_model(w, X_train, y_train, classifiers), max_iter=1000)

# ===== 问题3：模型评估 =====
# 评估函数
def evaluate_model(X_test, y_test, best_weights, classifiers):
    predictions = np.sign(np.sum(
        [best_weights[j] * weak_classifier(X_test, classifiers[j][0], classifiers[j][1]) 
        for j in range(len(classifiers))], axis=0))
    accuracy = np.mean(predictions == y_test)
    return accuracy

# 计算指标
def calculate_metrics(X_test, y_test, best_weights, classifiers):
    predictions = np.sign(np.sum(
        [best_weights[j] * weak_classifier(X_test, classifiers[j][0], classifiers[j][1]) 
        for j in range(len(classifiers))], axis=0))
    
    y_true = (y_test == 1).astype(int)
    y_pred = (predictions == 1).astype(int)
    
    TP = np.sum((y_true == 1) & (y_pred == 1))
    FP = np.sum((y_true == 0) & (y_pred == 1))
    FN = np.sum((y_true == 1) & (y_pred == 0))
    
    precision = TP / (TP + FP) if (TP + FP) > 0 else 0
    recall = TP / (TP + FN) if (TP + FN) > 0 else 0
    
    return precision, recall

# 评估并输出结果
accuracy = evaluate_model(X_test, y_test, best_weights, classifiers)
precision, recall = calculate_metrics(X_test, y_test, best_weights, classifiers)

print("\n=== 最终模型性能 ===")
print(f"准确率: {accuracy:.4f}")
print(f"精确率: {precision:.4f}")
print(f"召回率: {recall:.4f}")
print(f"最优权重组合: {best_weights}")